using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Comteck.Extensions;
using Comteck.Linq;
using Comteck.Localization;
using Comteck.Winforms.Controls.Loading;
using Comteck.Winforms.Utils;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Grid;
using ExpressMapper.Extensions;

namespace Comteck.Winforms {
  /// <summary>
  /// 列表和编辑界面相关的通用方法
  /// </summary>
  public static partial class FormCommonOperateExtensions {

    #region 1、通用列表的绑定功能
    /// <summary>
    /// 通用列表的绑定功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="destKeyType"></param>
    /// <param name="grid">需要绑定的控件</param>
    /// <param name="api">API路径地址</param>
    /// <param name="ajaxLoad">AJAX提示框</param>
    /// <param name="sourceKeyType"></param>
    /// <typeparam name="TKeyType"></typeparam>
    public static async Task BindSearchGet<T, TKeyType>(
      this GridControl grid, string api, AjaxLoadHelper ajaxLoad,
      Func<T, TKeyType> sourceKeyType, Func<T, TKeyType> destKeyType) {
      await BindSearch(grid, api, null, ajaxLoad, sourceKeyType, destKeyType, HttpClientMethod.Get);
    }

    /// <summary>
    /// 通用列表的绑定功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="destKeyType"></param>
    /// <param name="grid">需要绑定的控件</param>
    /// <param name="api">API路径地址</param>
    /// <param name="param">API参数</param>
    /// <param name="ajaxLoad">AJAX提示框</param>
    /// <param name="sourceKeyType"></param>
    /// <typeparam name="TKeyType"></typeparam>
    /// <param name="method"></param>
    public static async Task BindSearch<T, TKeyType>(
    this GridControl grid, string api,
    object param, AjaxLoadHelper ajaxLoad,
    Func<T, TKeyType> sourceKeyType,
    Func<T, TKeyType> destKeyType,
    HttpClientMethod method = HttpClientMethod.Post) {

      // 先校验是否绑定
      if (!(grid.DataSource is CKObservableCollection<T>) && !(grid.DataSource is CKBindingList<T>)) {
        DevHelper.ShowMsg(BaseResources.Grid_Datasource_Must_Be_ObservableCollection);
        return;
      }
      AjaxResponse<List<T>> result = null;
      using (ajaxLoad?.Show()) {
        switch (method) {
          case HttpClientMethod.Get:
            result = await SysGlobal.HttpClient.GetResult<AjaxResponse<List<T>>>(api);
            break;
          case HttpClientMethod.Post:
            result = await SysGlobal.HttpClient.PostResult<AjaxResponse<List<T>>>(api, param);
            break;
          default:
            break;
        }
      }

      if (grid.IsDisposed) {
        return;
      }

      var data1 = grid.DataSource as CKObservableCollection<T>;
      var data2 = grid.DataSource as CKBindingList<T>;

      if (result?.Code == 1) {
        if (data1 != null) {
          result.Data?.MapTo(data1, sourceKeyType, destKeyType);
        }
        if (data2 != null) {
          result.Data?.MapTo(data2, sourceKeyType, destKeyType);
        }
      } else {
        data1?.Clear();
        data2?.Clear();
        DevHelper.ShowMsg(result?.Message);
      }
    }

    #endregion

    #region 2、通用列表的删除功能

    /// <summary>
    /// 通用列表的删除功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid">需要绑定的控件</param>
    /// <param name="api">API路径地址</param>
    /// <param name="param">API参数</param>
    /// <param name="ajaxLoad">AJAX提示框</param>
    /// <param name="removeModel">待删除的对象</param>
    /// <param name="successAction">成功后事件</param>
    /// <returns></returns>
    public static async Task BindDelete<T>(this GridControl grid, string api, object param, AjaxLoadHelper ajaxLoad, T removeModel, Action successAction = null) {
      // 先校验是否绑定
      if (!(grid.DataSource is ObservableCollection<T>) && !(grid.DataSource is BindingList<T>)) {
        DevHelper.ShowMsg(BaseResources.Grid_Datasource_Must_Be_ObservableCollection);
        return;
      }

      if (DevHelper.ShowMsg(
        BaseResources.Delete_Selected_Confirm,
        null, MessageBoxButtons.YesNo,
        MessageBoxIcon.Warning,
        MessageBoxDefaultButton.Button2) == DialogResult.No) {
        return;
      }

      ajaxLoad?.Show();
      var result = await SysGlobal.HttpClient.PostResult<AjaxResponse>(api, param);
      ajaxLoad?.Hide();

      if (grid.IsDisposed) {
        return;
      }

      var data1 = grid.DataSource as ObservableCollection<T>;
      var data2 = grid.DataSource as BindingList<T>;

      if (result.Code == 1) {
        data1?.Remove(removeModel);
        data2?.Remove(removeModel);

        DevHelper.ShowMsg(BaseResources.Delete_Success);

        successAction?.Invoke();
      } else {
        DevHelper.ShowMsg(BaseResources.Delete_Failed_Reason, result.Message);
      }
    }

    #endregion

    #region 3、当编辑界面新增一条记录后，主动刷新主界面列表

    /// <summary>
    /// 当编辑界面新增一条记录后，主动刷新主界面列表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="entity"></param>
    /// <returns></returns>
    public static void BindAfterInsert<T>(this GridView grid, object entity) {
      // 先校验是否绑定
      if (!(grid.DataSource is ObservableCollection<T>) && !(grid.DataSource is BindingList<T>)) {
        DevHelper.ShowMsg(BaseResources.Grid_Datasource_Must_Be_ObservableCollection);
        return;
      }

      if (!(entity is T entityValue)) {
        DevHelper.ShowMsg(BaseResources.Save_After_Type_Error, typeof(T).Name, entity.GetType().Name);
        return;
      }

      //
      var data1 = grid.DataSource as ObservableCollection<T>;
      var data2 = grid.DataSource as BindingList<T>;

      // 添加并定位到第一行
      data1?.Insert(0, entityValue);
      data2?.Insert(0, entityValue);
      grid.MoveFirst();
      grid.ClearSelection();
      grid.SelectRow(0);
    }

    #endregion

    #region 4、当编辑界面新增一条记录后，主动刷新主界面列表

    /// <summary>
    /// 当编辑界面新增一条记录后，主动刷新主界面列表
    /// </summary>
    /// <param name="grid"></param>
    /// <param name="oldValue">原值</param>
    /// <param name="newValue">新值</param>
    /// <returns></returns>
    public static void BindAfterUpdate<T>(this GridView grid, T oldValue, object newValue) {
      if (!(newValue is T entityValue)) {
        DevHelper.ShowMsg(BaseResources.Save_After_Type_Error, typeof(T).Name, newValue.GetType().Name);
        return;
      }

      // 映射结果
      entityValue.MapTo(oldValue);
      grid?.RefreshData();
    }

    #endregion

    #region 多条记录 add by geping@2019-06-07

    /// <summary>
    /// 当编辑界面新增多条记录后，主动刷新主界面列表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="list"></param>
    /// <returns></returns>
    public static void BindAfterInsertBulk<T>(this GridView grid, List<T> list) {
      // 先校验是否绑定
      if (!(grid.DataSource is ObservableCollection<T>) && !(grid.DataSource is BindingList<T>)) {
        DevHelper.ShowMsg(BaseResources.Grid_Datasource_Must_Be_ObservableCollection);
        return;
      }

      var data1 = grid.DataSource as ObservableCollection<T>;
      var data2 = grid.DataSource as BindingList<T>;

      // 添加并定位到第一行
      list.ForEach(item => {
        data1?.Insert(0, item);
        data2?.Insert(0, item);
      });
      grid.MoveFirst();
      grid.ClearSelection();
      grid.SelectRow(0);
    }
    #endregion
  }
}
